

package config

import (
    "bytes"
    "fmt"
    "os"
    "path/filepath"

    "github.com/go-ini/ini"
    "libgo/utils"
)

func (s *Config) Save(fname string) error {
    buf := &bytes.Buffer{}
    ctx := ini.Empty()
    if err := ini.ReflectFrom(ctx, s); err != nil {
        return err
    }

    if _, err := ctx.WriteTo(buf); err != nil {
        return err
    }


    if !filepath.IsAbs(fname) {
        fname = filepath.Join(utils.ProjectRoot(), fname)
    }
    tmpName := filepath.Join(filepath.Dir(fname), filepath.Base(fname)+".tmp")
    _ = os.MkdirAll(filepath.Dir(tmpName), 0666)

    fp, err := os.OpenFile(tmpName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
    if err != nil {
        logger.Error("openfile failed:", err.Error())
        return fmt.Errorf("openfile failed: %s", err.Error())
    }
    defer fp.Close()

    if _, err := buf.WriteTo(fp); err != nil {
        return fmt.Errorf("write file failed: %s", err)
    }

    if err := fp.Sync(); err != nil {
        return err
    }
    if err := fp.Close(); err != nil {
        return err
    }

    if err := os.Rename(tmpName, fname); err != nil {
        return err
    }

    fsync()

    return nil
}

func (s *Config) Load(fname string) error {
    if !filepath.IsAbs(fname) {
        fname = filepath.Join(utils.ProjectRoot(), fname)
    }
    fname = filepath.Clean(fname)
    logger.Info("配置文件路径: ", fname)


    if fp, err := os.OpenFile(fname, os.O_RDONLY, 0600); err != nil {
        if os.IsNotExist(err) {
            logger.Info("配置文件不存在，创建出厂配置")
            cfg := Default()
            if err := cfg.Save(fname); err != nil {
                logger.Error("创建出厂配置失败", err.Error())
                return err
            } else {
                logger.Info("创建出厂配置成功")
            }
        }
    } else {
        _ = fp.Close()
    }


    ctx, err := ini.LoadSources(ini.LoadOptions{
        UnescapeValueDoubleQuotes: true,

    }, fname)
    if err != nil {
        logger.Error("加载配置文件失败", err)
        return err
    }


    if err = ctx.MapTo(s); err != nil {
        logger.Error("impossible error: " + err.Error())
        return err
    }
    return nil
}

func NewFromFile(fname string) (*Config, error) {
    cfg := Default()
    err := cfg.Load(fname)
    return cfg, err
}
